﻿namespace TestTool.GUI.Utils
{
    using System;
    using System.Globalization;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Threading;
    using TestTool.GUI.Controllers;
    using TestTool.GUI.Data;
    using TestTool.HttpTransport;
    using TestTool.HttpTransport.Interfaces;
    using TestTool.HttpTransport.Interfaces.Exceptions;
    using TestTool.Tests.Common.TestBase;
    using TestTool.Tests.Common.Transport;
    using TestTool.Tests.Definitions.Exceptions;

    internal abstract class BaseServiceProvider<T, TChannel> : ITrafficListener, IExecutionController, ITransportController, IChannelController where T: ClientBase<TChannel> where TChannel: class
    {
        private T _client;
        protected CredentialsProvider _credentialsProvider;
        private int _messageTimeout;
        private TestTool.HttpTransport.Interfaces.Security _security;
        protected string _serviceAddress;
        private AutoResetEvent _stopEvent;

        public event Action<string, Exception> ExceptionThrown;

        public event Action<string, FaultException> FaultThrown;

        public event Action OperationCompleted;

        public event Action OperationStarted;

        public event Action<string> ResponseReceived;

        protected BaseServiceProvider(string serviceAddress, int messageTimeout)
        {
            this._serviceAddress = serviceAddress;
            this._messageTimeout = messageTimeout;
            this._security = TestTool.HttpTransport.Interfaces.Security.None;
            this._stopEvent = new AutoResetEvent(false);
            this.CreateClient();
        }

        protected Action ConstructSecurityTolerantAction(Action unsecure)
        {
            return delegate {
                try
                {
                    ((BaseServiceProvider<T, TChannel>) this).Security = TestTool.HttpTransport.Interfaces.Security.None;
                    unsecure();
                }
                catch (AccessDeniedException)
                {
                    ((BaseServiceProvider<T, TChannel>) this).Security = TestTool.HttpTransport.Interfaces.Security.Digest;
                    unsecure();
                }
                catch (FaultException exception)
                {
                    if (!exception.IsValidOnvifFault("Sender/NotAuthorized") && !exception.IsValidOnvifFault("Sender/NotAuthorized/SenderNotAuthorized"))
                    {
                        throw exception;
                    }
                    ((BaseServiceProvider<T, TChannel>) this).Security = TestTool.HttpTransport.Interfaces.Security.WS;
                    unsecure();
                }
            };
        }

        private void CreateClient()
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            EndpointController controller = new EndpointController(new EndpointAddress(this._serviceAddress));
            this._credentialsProvider = new CredentialsProvider();
            this._credentialsProvider.Username = deviceEnvironment.Credentials.UserName;
            this._credentialsProvider.Password = deviceEnvironment.Credentials.Password;
            this._credentialsProvider.Security = this._security;
            Binding binding = new HttpBinding(new IChannelController[] { this, controller, this._credentialsProvider });
            this._client = this.CreateClient(binding, new EndpointAddress(this._serviceAddress));
            ServicePointManager.Expect100Continue = false;
            SecurityBehavior item = new SecurityBehavior {
                CredentialsProvider = this._credentialsProvider
            };
            this._client.Endpoint.Behaviors.Add(item);
            this._client.InnerChannel.OperationTimeout = new TimeSpan(0, 0, 0, 0, this._messageTimeout);
        }

        public abstract T CreateClient(Binding binding, EndpointAddress address);
        public void LogRequest(string request)
        {
        }

        public void LogResponse(string response)
        {
            if (this.EnableLogResponse && (this.ResponseReceived != null))
            {
                this.ResponseReceived(response);
            }
        }

        protected void ProcessRequest(Action action)
        {
            bool flag = false;
            try
            {
                this.ReportOperationStarted();
                action();
            }
            catch (FaultException exception)
            {
                this.ReportFault(exception);
            }
            catch (StopEventException)
            {
                flag = true;
            }
            catch (Exception exception2)
            {
                this.ReportException(exception2);
            }
            finally
            {
                if (!flag)
                {
                    this.ReportOperationCompleted();
                }
            }
        }

        protected void ReportException(Exception ex)
        {
            if (this.ExceptionThrown != null)
            {
                this.ExceptionThrown(string.Empty, ex);
            }
        }

        protected void ReportException(Exception ex, string stage)
        {
            if (this.ExceptionThrown != null)
            {
                this.ExceptionThrown(stage, ex);
            }
        }

        protected void ReportFault(FaultException ex)
        {
            if (this.FaultThrown != null)
            {
                this.FaultThrown(string.Empty, ex);
            }
        }

        protected void ReportOperationCompleted()
        {
            if (this.OperationCompleted != null)
            {
                this.OperationCompleted();
            }
        }

        protected void ReportOperationStarted()
        {
            if (this.OperationStarted != null)
            {
                this.OperationStarted();
            }
        }

        public void ReportStop()
        {
            throw new StopEventException();
        }

        protected void RunInBackground(Action action)
        {
            this.ReportOperationStarted();
            new Thread(new ThreadStart(() => ((BaseServiceProvider<T, TChannel>) this).ProcessRequest(action))) { CurrentUICulture = CultureInfo.InvariantCulture }.Start();
        }

        public void Stop()
        {
            this._stopEvent.Set();
        }

        public string Address
        {
            get
            {
                return this._client.Endpoint.Address.Uri.OriginalString;
            }
            set
            {
                if (this._serviceAddress != value)
                {
                    this._serviceAddress = value;
                    this.CreateClient();
                }
            }
        }

        protected T Client
        {
            get
            {
                return this._client;
            }
        }

        protected bool EnableLogResponse { get; set; }

        public TestTool.HttpTransport.Interfaces.Security Security
        {
            get
            {
                return this._security;
            }
            set
            {
                this._security = value;
                if (this._credentialsProvider != null)
                {
                    this._credentialsProvider.Security = value;
                }
            }
        }

        public WaitHandle StopEvent
        {
            get
            {
                return this._stopEvent;
            }
        }

        public int Timeout
        {
            get
            {
                return (int) this._client.InnerChannel.OperationTimeout.TotalMilliseconds;
            }
            set
            {
                this._messageTimeout = value;
                this._client.InnerChannel.OperationTimeout = new TimeSpan(0, 0, 0, 0, this._messageTimeout);
            }
        }
    }
}

